From d61f6ff39306efff512b4e4b80c642ca2acf7dce Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 23 Sep 2017 01:59:50 -0400 Subject: [PATCH] vulkan: Implement blend modes This is another example for a 2-texture shader. So far, only separable blend modes are implemented. The implementation is not optimized, with an if-else cascade in the shader. --- gsk/gskvulkanblendmodepipeline.c | 146 ++++++++++++++ gsk/gskvulkanblendmodepipelineprivate.h | 37 ++++ gsk/gskvulkanrender.c | 4 + gsk/gskvulkanrenderpass.c | 96 ++++++++- gsk/gskvulkanrenderprivate.h | 3 + gsk/meson.build | 1 + .../vulkan/blendmode-clip-rounded.frag.spv | Bin 0 -> 22744 bytes .../vulkan/blendmode-clip-rounded.vert.spv | Bin 0 -> 5856 bytes gsk/resources/vulkan/blendmode-clip.frag.spv | Bin 0 -> 15972 bytes gsk/resources/vulkan/blendmode-clip.vert.spv | Bin 0 -> 5856 bytes .../vulkan/blendmode-rect-rounded.frag.spv | Bin 0 -> 22744 bytes gsk/resources/vulkan/blendmode-rect.frag.spv | Bin 0 -> 15972 bytes gsk/resources/vulkan/blendmode.frag | 183 ++++++++++++++++++ gsk/resources/vulkan/blendmode.frag.spv | Bin 0 -> 15972 bytes gsk/resources/vulkan/blendmode.vert | 44 +++++ gsk/resources/vulkan/blendmode.vert.spv | Bin 0 -> 4124 bytes gsk/resources/vulkan/meson.build | 2 + 17 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 gsk/gskvulkanblendmodepipeline.c create mode 100644 gsk/gskvulkanblendmodepipelineprivate.h create mode 100644 gsk/resources/vulkan/blendmode-clip-rounded.frag.spv create mode 100644 gsk/resources/vulkan/blendmode-clip-rounded.vert.spv create mode 100644 gsk/resources/vulkan/blendmode-clip.frag.spv create mode 100644 gsk/resources/vulkan/blendmode-clip.vert.spv create mode 100644 gsk/resources/vulkan/blendmode-rect-rounded.frag.spv create mode 100644 gsk/resources/vulkan/blendmode-rect.frag.spv create mode 100644 gsk/resources/vulkan/blendmode.frag create mode 100644 gsk/resources/vulkan/blendmode.frag.spv create mode 100644 gsk/resources/vulkan/blendmode.vert create mode 100644 gsk/resources/vulkan/blendmode.vert.spv diff --git a/gsk/gskvulkanblendmodepipeline.c b/gsk/gskvulkanblendmodepipeline.c new file mode 100644 index 0000000000..062921e0b2 --- /dev/null +++ b/gsk/gskvulkanblendmodepipeline.c @@ -0,0 +1,146 @@ +#include "config.h" + +#include "gskvulkanblendmodepipelineprivate.h" + +struct _GskVulkanBlendModePipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance; + +struct _GskVulkanBlendModeInstance +{ + float rect[4]; + float start_tex_rect[4]; + float end_tex_rect[4]; + guint32 blend_mode; +}; + +G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanBlendModeInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32_UINT, + .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode), + } + }; + static const VkPipelineVertexInputStateCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions), + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription), + .pVertexAttributeDescriptions = vertexInputAttributeDescription + }; + + return &info; +} + +static void +gsk_vulkan_blend_mode_pipeline_finalize (GObject *gobject) +{ + //GskVulkanBlendModePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_blend_mode_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_blend_mode_pipeline_class_init (GskVulkanBlendModePipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blend_mode_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_blend_mode_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_blend_mode_pipeline_init (GskVulkanBlendModePipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline) +{ + return sizeof (GskVulkanBlendModeInstance); +} + +void +gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline, + guchar *data, + const graphene_rect_t *bounds, + const graphene_rect_t *start_bounds, + const graphene_rect_t *end_bounds, + GskBlendMode blend_mode) +{ + GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data; + + instance->rect[0] = bounds->origin.x; + instance->rect[1] = bounds->origin.y; + instance->rect[2] = bounds->size.width; + instance->rect[3] = bounds->size.height; + + instance->start_tex_rect[0] = (bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width; + instance->start_tex_rect[1] = (bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height; + instance->start_tex_rect[2] = (bounds->size.width + bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width; + instance->start_tex_rect[3] = (bounds->size.height + bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height; + + instance->end_tex_rect[0] = (bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width; + instance->end_tex_rect[1] = (bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height; + instance->end_tex_rect[2] = (bounds->size.width + bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width; + instance->end_tex_rect[3] = (bounds->size.height + bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height; + + instance->blend_mode = blend_mode; +} + +gsize +gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/gskvulkanblendmodepipelineprivate.h b/gsk/gskvulkanblendmodepipelineprivate.h new file mode 100644 index 0000000000..67822e4f9b --- /dev/null +++ b/gsk/gskvulkanblendmodepipelineprivate.h @@ -0,0 +1,37 @@ +#ifndef __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ + +#include + +#include "gskvulkanpipelineprivate.h" +#include "gskenums.h" + +G_BEGIN_DECLS + +typedef struct _GskVulkanBlendModePipelineLayout GskVulkanBlendModePipelineLayout; + +#define GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE (gsk_vulkan_blend_mode_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK, VULKAN_BLEND_MODE_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline); +void gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline, + guchar *data, + const graphene_rect_t *bounds, + const graphene_rect_t *start_bounds, + const graphene_rect_t *end_bounds, + GskBlendMode blend_mode); +gsize gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + + +G_END_DECLS + +#endif /* __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index 06b622db59..007f3d4ac2 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -10,6 +10,7 @@ #include "gskvulkanpipelineprivate.h" #include "gskvulkanrenderpassprivate.h" +#include "gskvulkanblendmodepipelineprivate.h" #include "gskvulkanblendpipelineprivate.h" #include "gskvulkanblurpipelineprivate.h" #include "gskvulkanborderpipelineprivate.h" @@ -392,6 +393,9 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self, { "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new }, { "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new }, { "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new }, + { "blendmode", 2, gsk_vulkan_blend_mode_pipeline_new }, + { "blendmode-clip", 2, gsk_vulkan_blend_mode_pipeline_new }, + { "blendmode-clip-rounded", 2, gsk_vulkan_blend_mode_pipeline_new }, }; g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 866a4eaa73..3f9c7aa0c6 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -6,6 +6,7 @@ #include "gskrendernodeprivate.h" #include "gskrenderer.h" #include "gskroundedrectprivate.h" +#include "gskvulkanblendmodepipelineprivate.h" #include "gskvulkanblendpipelineprivate.h" #include "gskvulkanblurpipelineprivate.h" #include "gskvulkanborderpipelineprivate.h" @@ -50,6 +51,7 @@ typedef enum { GSK_VULKAN_OP_COLOR_TEXT, /* GskVulkanOpCrossFade */ GSK_VULKAN_OP_CROSS_FADE, + GSK_VULKAN_OP_BLEND_MODE, /* GskVulkanOpPushConstants */ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS, } GskVulkanOpType; @@ -180,10 +182,28 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, return; case GSK_REPEAT_NODE: case GSK_SHADOW_NODE: - case GSK_BLEND_NODE: default: FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name); + case GSK_BLEND_NODE: + if (gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_COLOR || + gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_HUE || + gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_SATURATION || + gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_LUMINOSITY) + FALLBACK ("Nonseparable blend modes not implemented\n"); + if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) + pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED; + else + FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type); + op.type = GSK_VULKAN_OP_BLEND_MODE; + op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type); + g_array_append_val (self->render_ops, op); + return; + case GSK_CROSS_FADE_NODE: if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE; @@ -758,6 +778,24 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_BLEND_MODE: + { + GskRenderNode *top = gsk_blend_node_get_top_child (op->crossfade.node); + GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->crossfade.node); + + op->crossfade.start = gsk_vulkan_render_pass_get_node_as_texture (self, + render, + uploader, + top, + &top->bounds); + op->crossfade.end = gsk_vulkan_render_pass_get_node_as_texture (self, + render, + uploader, + bottom, + &bottom->bounds); + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: @@ -843,6 +881,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) n_bytes += op->crossfade.vertex_count; break; + case GSK_VULKAN_OP_BLEND_MODE: + op->crossfade.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->crossfade.pipeline)); + n_bytes += op->crossfade.vertex_count; + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -1049,6 +1092,22 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_BLEND_MODE: + { + GskRenderNode *top = gsk_blend_node_get_top_child (op->crossfade.node); + GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->crossfade.node); + + op->crossfade.vertex_offset = offset + n_bytes; + gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->crossfade.pipeline), + data + n_bytes + offset, + &op->crossfade.node->bounds, + &top->bounds, + &bottom->bounds, + gsk_blend_node_get_blend_mode (op->crossfade.node)); + n_bytes += op->crossfade.vertex_count; + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -1091,6 +1150,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, break; case GSK_VULKAN_OP_CROSS_FADE: + case GSK_VULKAN_OP_BLEND_MODE: op->crossfade.descriptor_set_start = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.start); op->crossfade.descriptor_set_end = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.end); break; @@ -1432,6 +1492,40 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, current_draw_index, 1); break; + case GSK_VULKAN_OP_BLEND_MODE: + if (current_pipeline != op->crossfade.pipeline) + { + current_pipeline = op->crossfade.pipeline; + vkCmdBindPipeline (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline (current_pipeline)); + vkCmdBindVertexBuffers (command_buffer, + 0, + 1, + (VkBuffer[1]) { + gsk_vulkan_buffer_get_buffer (vertex_buffer) + }, + (VkDeviceSize[1]) { op->crossfade.vertex_offset }); + current_draw_index = 0; + } + + vkCmdBindDescriptorSets (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline), + 0, + 2, + (VkDescriptorSet[2]) { + gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_start), + gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_end) + }, + 0, + NULL); + + current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline), + command_buffer, + current_draw_index, 1); + break; + default: g_assert_not_reached (); break; diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h index 6739bb5941..ed35019c3f 100644 --- a/gsk/gskvulkanrenderprivate.h +++ b/gsk/gskvulkanrenderprivate.h @@ -43,6 +43,9 @@ typedef enum { GSK_VULKAN_PIPELINE_CROSS_FADE, GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP, GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED, + GSK_VULKAN_PIPELINE_BLEND_MODE, + GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP, + GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED, /* add more */ GSK_VULKAN_N_PIPELINES } GskVulkanPipelineType; diff --git a/gsk/meson.build b/gsk/meson.build index 072c140da3..e91985af8e 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -54,6 +54,7 @@ gsk_private_vulkan_compiled_shaders_deps = [] if have_vulkan gsk_private_sources += files([ + 'gskvulkanblendmodepipeline.c', 'gskvulkanblendpipeline.c', 'gskvulkanblurpipeline.c', 'gskvulkanborderpipeline.c', diff --git a/gsk/resources/vulkan/blendmode-clip-rounded.frag.spv b/gsk/resources/vulkan/blendmode-clip-rounded.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..4ede20eb07cb298a1cded6064e3c32c752b98818 GIT binary patch literal 22744 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 Bnm7Oe literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/blendmode-clip.vert.spv b/gsk/resources/vulkan/blendmode-clip.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..499a74abe1112feda521426ff3ae08903e0a710d GIT binary patch literal 5856 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 GYyA&pDw;w7 literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/blendmode.frag b/gsk/resources/vulkan/blendmode.frag new file mode 100644 index 0000000000..803a538d1d --- /dev/null +++ b/gsk/resources/vulkan/blendmode.frag @@ -0,0 +1,183 @@ +#version 420 core + +#include "clip.frag.glsl" + +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec2 inStartTexCoord; +layout(location = 2) in vec2 inEndTexCoord; +layout(location = 3) flat in uint inBlendMode; + +layout(set = 0, binding = 0) uniform sampler2D startTexture; +layout(set = 1, binding = 0) uniform sampler2D endTexture; + +layout(location = 0) out vec4 color; + +vec3 +multiply (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = source * backdrop; + return mix (source, result, opacity); +} + +vec3 +difference (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = abs (source - backdrop); + return mix (source, result, opacity); +} + +vec3 +screen (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = source + backdrop - source * backdrop; + return mix (source, result, opacity); +} + +float +hard_light (float source, float backdrop) +{ + if (source <= 0.5) + return 2 * backdrop * source; + else + return 2 * (backdrop + source - backdrop * source) - 1; +} + +vec3 +hard_light (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = vec3 (hard_light (source.r, backdrop.r), + hard_light (source.g, backdrop.g), + hard_light (source.b, backdrop.b)); + return mix (source, result, opacity); +} + +float +soft_light (float source, float backdrop) +{ + float db; + + if (backdrop <= 0.25) + db = ((16 * backdrop - 12) * backdrop + 4) * backdrop; + else + db = sqrt (backdrop); + + if (source <= 0.5) + return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop); + else + return backdrop + (2 * source - 1) * (db - backdrop); +} + +vec3 +soft_light (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = vec3 (soft_light (source.r, backdrop.r), + soft_light (source.g, backdrop.g), + soft_light (source.b, backdrop.b)); + return mix (source, result, opacity); +} + +vec3 +overlay (vec3 source, vec3 backdrop, float opacity) +{ + return hard_light (backdrop, source, opacity); +} + +vec3 +darken (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = min (source, backdrop); + return mix (source, result, opacity); +} + +vec3 +lighten (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = max (source, backdrop); + return mix (source, result, opacity); +} + +float +color_dodge (float source, float backdrop) +{ + return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0); +} + +vec3 +color_dodge (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = vec3 (color_dodge (source.r, backdrop.r), + color_dodge (source.g, backdrop.g), + color_dodge (source.b, backdrop.b)); + return mix (source, result, opacity); +} + + +float +color_burn (float source, float backdrop) +{ + return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0); +} + +vec3 +color_burn (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = vec3 (color_burn (source.r, backdrop.r), + color_burn (source.g, backdrop.g), + color_burn (source.b, backdrop.b)); + return mix (source, result, opacity); +} + +vec3 +exclusion (vec3 source, vec3 backdrop, float opacity) +{ + vec3 result = backdrop + source - 2.0 * backdrop * source; + return mix (source, result, opacity); +} + +float +combine (float source, float backdrop) +{ + return source + backdrop * (1 - source); +} + +void main() +{ + vec4 source = texture (startTexture, inStartTexCoord); + vec4 backdrop = texture (endTexture, inEndTexCoord); + vec3 rgb = vec3(1,0,0); + float a = 1; + + a = combine (source.a, backdrop.a); + + if (inBlendMode == 0) // default + { + rgb = source.rgb; + a = source.a; + } + else if (inBlendMode == 1) + rgb = multiply (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 2) + rgb = screen (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 3) + rgb = overlay (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 4) + rgb = darken (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 5) + rgb = lighten (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 6) + rgb = color_dodge (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 7) + rgb = color_burn (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 8) + rgb = hard_light (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 9) + rgb = soft_light (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 10) + rgb = difference (source.rgb, backdrop.rgb, backdrop.a); + else if (inBlendMode == 11) + rgb = exclusion (source.rgb, backdrop.rgb, backdrop.a); + else + discard; + + color = clip (inPos, vec4 (rgb, a)); +} diff --git a/gsk/resources/vulkan/blendmode.frag.spv b/gsk/resources/vulkan/blendmode.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..21484c8e1815cde307698321abe329557fd3c4cb GIT binary patch literal 15972 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 Bnm7Oe literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/blendmode.vert b/gsk/resources/vulkan/blendmode.vert new file mode 100644 index 0000000000..35b8356c90 --- /dev/null +++ b/gsk/resources/vulkan/blendmode.vert @@ -0,0 +1,44 @@ +#version 420 core + +#include "clip.vert.glsl" + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inStartTexRect; +layout(location = 2) in vec4 inEndTexRect; +layout(location = 3) in uint inBlendMode; + +layout(location = 0) out vec2 outPos; +layout(location = 1) out vec2 outStartTexCoord; +layout(location = 2) out vec2 outEndTexCoord; +layout(location = 3) flat out uint outBlendMode; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +void main() { + vec4 rect = clip (inRect); + vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + outPos = pos; + + vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw, + rect.zw / inRect.zw); + vec4 starttexrect = vec4(inStartTexRect.xy + inStartTexRect.zw * texrect.xy, + inStartTexRect.zw * texrect.zw); + vec4 endtexrect = vec4(inEndTexRect.xy + inEndTexRect.zw * texrect.xy, + inEndTexRect.zw * texrect.zw); + + outStartTexCoord = starttexrect.xy + starttexrect.zw * offsets[gl_VertexIndex]; + outEndTexCoord = endtexrect.xy + endtexrect.zw * offsets[gl_VertexIndex]; + + outBlendMode = inBlendMode; +} diff --git a/gsk/resources/vulkan/blendmode.vert.spv b/gsk/resources/vulkan/blendmode.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..614f7cfc501987a699e350b69aa874910b2f545a GIT binary patch literal 4124 zcmZ9OX?GM=6h#Y?P8b9QWYDD;1Qlcul~H6iHfS(m5NDf^?vT=?I;J}zI6@Fb#Q`To zzxpHnqRYK2bwjN@*5TcA?(ps#s-a`y#_l9pz@KHwU&-uPkt~EK$<; zwQ7HVwXe4}G(KKywXcjeYNKh^sMXVn#!x$*Y8bbu6qja0qm%V=K!u2MFO{UiK9Xc; zG#%eOHN5KpwlPbXEy|ShmCViI;Z~#F%K4-7{O&2u&g2>9_rS*oCkDruE9_&FylHM% zzV}O`weyXMc4PWvR&Puj)0I3&4EjK0V%7ykoz=DVHCt&rZDx5*&(C4*Ugm+x*2wW@ z)@l!CbZKs9t{XEpHJ;Zp&UfL$1x0&lBjr7t;UYa#K zll|!9tjUyf@3J}BrpH-cg|ox_813jc*FyY*OK|mhTMx*eHvfYSwu@##i#UmuC0m zDtq;Q*Bii)`+j{lPlFTWcy|spN0mEQ^Gr{a?xB+N%G|wdggdO^-8lH*k_SL&-j{Jl zN}6@m21=Uuq;>(gzV(c=U+<>ezu%nP+WI|LdBo2YJp7*FJ%2}jcFWPs^&IuNzT9s& z_$n$|a|2%e+H0`7n0vrl;@z*@@3M!#7cr}e4e-TX5+238g3swz_GR9{^}U> z2;8$YN6q>xnDwb2D7fFZn)%MFfMXl?V(x=LO+?IU>?FB*IAYeo)QkyjZNb$;TZb*5 z)fVS{JOp{;%cRMYRh>$6wSWJ|8!^ZQPXRX1Pm8;<<#*zVi> z_1uqd*Lv1|p4q!oGgt0!kD6y;&E3GU4!(!kT<>!|RrfN7rXF?oVSBgwttrJ)1B0of{+fjC|+rF}UwMxbZU};^n?`x$FI2*uF3G<#!5A{~y@a z3cuX9ueOJGBPCB6}RQ;8d2oyYw>E$3$iKg4RjXW!I8 z)-q-T@V)5kDfoW6(f2s;cdG~Jw=cEGeF9sppJ>neNuVYi?l)qe!Y;>dhN}tB!*ej! zH?s}+29MH*?{5dNZ*^l_>lvVagBbZvU`_RFh4w7AJ?XQ5&rQv`z9Iij_g(o$t?PSw z5va#H2eHjNO^)Beq1?w`jL;5a8|QupI1A722ryQk-@V`TZEEN{3S8$%Zdda6dmP(u z$6oAJZd~;7GPZr_>t&Yfv)&0%KHHOprtT=;!z*y_JMQdNY&GF9_Ih!Cec0AACe}KI zUCw_Et|sChZx;FeXx1<$@&~ZXy`F}viO7%GGic?t&cfA1#Kv0Z(5z)l+{^3O_TUKZ zJhqzq4DAhU^BtkRiLGW_-054`*0hE>#&{o9W_{83yV(A|#2LSbttK4h`*u@UO;oLs5^+QCLGp{@8Kf0wTy}HVF=q^^hM1&c6t23BAjQ8R1pT5}RICc}nxqXDK zCLGp`*a_@%YzwX?VviBqMk}AkBwS56tQ+Ssg>5Zk;yx~8+l#)aIgMRj{|a19%wPXw zwDS6&z|};=#`>S4S<9F>)6cN&!4cZ$*lOkb_yTUeBjT=NtCjEL8r+)JFy|`pJ~C!~ zvB&G!-cj7gm)L5;VaXa6(IYSGj8*zPI%{{dS~ILiJ12rtL}1XmOD`@fA=?*C`F{i{d+zhJ9J z|G#2eQ$70s4cngd+5atOHES$q{uA5<`tB6`U%K80{QpTe+EUMT>TjPJs9Yxgu literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/meson.build b/gsk/resources/vulkan/meson.build index 6e61885e65..160bc0d6e4 100644 --- a/gsk/resources/vulkan/meson.build +++ b/gsk/resources/vulkan/meson.build @@ -8,6 +8,7 @@ gsk_private_vulkan_fragment_shaders = [ 'blend.frag', + 'blendmode.frag', 'blur.frag', 'border.frag', 'color.frag', @@ -21,6 +22,7 @@ gsk_private_vulkan_fragment_shaders = [ gsk_private_vulkan_vertex_shaders = [ 'blend.vert', + 'blendmode.vert', 'blur.vert', 'border.vert', 'color.vert', -- 2.30.2